package models

import (
	"database/sql"
	"errors"
	"fmt"
	"strconv"
)

func 输出技能信息(tx *Buff, id int32) {
	v, _ := 技能_获取技能信息(id)
	tx.AddStringAndLen(v.V技能英文名)
	tx.AddStringAndLen(v.V技能中文名)
	tx.AddStringAndLen(v.V技能备注)
	tx.AddBytes(String2Byte("0000000000"))
	要求点数 := 0
	bf := CreateBuff(50)
	for i := uint8(0); i < 10; i++ {
		if t, ok := v.V属性要求[i]; ok == true {
			bf.AddByte(byte(i))
			bf.AddInt32(int32(t))
			要求点数++
		}
	}
	tx.AddByte(byte(要求点数))
	tx.AddBytes(bf.Buff)

	要求技能数量 := 0
	bf = CreateBuff(50)
	for kk, vv := range v.V技能要求 {
		bf.AddStringAndLen(kk)
		bf.AddInt32(int32(vv))
		要求技能数量++
	}
	tx.AddByte(byte(要求技能数量))
	tx.AddBytes(bf.Buff)
}
func (rt *RunTime) 输出高阶技能信息(tx *Buff, 技能信息 *Struct技能信息) {
	tx.AddStringAndLen(技能信息.V技能英文名)
	tx.AddStringAndLen(技能信息.V技能中文名)
	tx.AddStringAndLen(技能信息.V技能备注)
	实时技能, _ := rt.技能_获取实时技能列表(技能信息.V技能英文名)
	tx.AddInt32(int32(实时技能.V技能等级))
	tx.AddFloat(float32(实时技能.V冷却时间)) //$未知,应该是间隔
	tx.AddInt32(int32(实时技能.V魔法消耗))
	tx.AddInt32(int32(实时技能.V攻击距离) * 100)
}
func (rt *RunTime) 技能_设置技能_英文(技能类型 byte, 技能名称 string) *Struct技能信息 {
	var 技能信息 *Struct技能信息
	if len(技能名称) != 0 {
		if t, err := 技能_获取技能信息_英文(技能名称, rt.V角色.V职业); err != nil {
			panic("非法技能")
		} else {
			技能信息 = t
		}
	}
	switch 技能类型 {
	case 0:
		rt.V角色.V物理攻击技能栏 = 技能名称
	case 1:
		rt.V角色.V物理魔法攻击技能栏 = 技能名称
	case 2:
		rt.V角色.V魔法攻击技能栏 = 技能名称
	}
	return 技能信息
}

//第二个参数为等级，表示要学习哪个级别的技能
func (rt *RunTime) 技能_等级增加(技能英文名称 string, 等级 uint16) error {
	技能信息, err := 技能_获取技能信息_英文(技能英文名称, rt.V角色.V职业)
	if err != nil {
		return err
	}
	if 技能, ok := rt.V技能列表[技能信息.Id]; ok == true {
		学习技能最高等级 := uint16(20)
		if t, err := strconv.Atoi(GetConfig("技能", "学习最高等级", "20")); err == nil {
			学习技能最高等级 = uint16(t)
		}
		if 技能.V技能等级 >= 学习技能最高等级 {
			技能.V经验 = 0
			技能.V技能等级 = 学习技能最高等级
			return errors.New(fmt.Sprintf("学习等级最高%d级", 学习技能最高等级))
		} else {
			if (技能.V技能等级 + 1) < 等级 { //0-99 外部写的是1-100
				return errors.New("您技能等级不足，无法升级到指定技能等级")
			}
			if (技能.V技能等级 + 1) > 等级 { //0-99 外部写的是1-100
				return errors.New("已学会的技能书.")
			}
			技能.V经验 = 0
			技能信息, _ = 技能_获取技能信息(技能.V技能ID)
			总经验 := 技能信息.V需求经验[技能.V技能等级]
			技能.V技能等级++
			技能.V经验 -= 总经验
			if 技能.V经验 < 0 {
				技能.V经验 = 0
			}
			技能.Stata.V修改 = true
			技能.Stata.V更新字段["V技能等级"] = true
			实时技能, _ := rt.技能_获取实时技能列表(技能英文名称)
			rt.技能_设置技能等级(技能信息, 实时技能, true)
			return nil
		}
	}
	if 等级 != 0 {
		return errors.New("此技能必须从1级学起!")
	}
	技能 := &Struct技能列表{}
	技能.V技能ID = 技能信息.Id
	技能.Uid = rt.V角色.Id
	技能.V技能等级 = 0
	//技能.V最后经验百分比 = 0
	技能.Stata.V更新字段 = make(map[string]bool)

	if _, err := db.Insert(技能); err != nil { //添加技能到那数据库
		return err
	}
	rt.V技能列表[技能.V技能ID] = 技能 //注意，这里的ID是技能信息中的ID
	实时技能, _ := rt.技能_获取实时技能列表(技能英文名称)
	rt.技能_发送学会新技能(技能信息, 实时技能)
	return nil
}
func (rt *RunTime) 技能_检测新技能() bool {
	角色 := rt.V角色
	技能信息表 := 技能_获取指定职业技能(角色.V职业)
	for _, v := range 技能信息表 {
		if v.V攻击类型 > 2 { //不是普通技能
			continue
		}
		/*if v.V技能等级 != "普通技能" {
			continue
		}*/
		if _, ok := rt.V技能列表[v.Id]; ok == true { //已经学习的技能
			continue
		}
		符合 := true
		for k, v := range v.V属性要求 {
			var 比较值 uint16
			switch k {
			case 0:
				比较值 = 角色.V等级
			case 1:
				比较值 = 角色.V力量
			case 2:
				比较值 = 角色.V敏捷
			case 3:
				比较值 = 角色.V精神
			case 4:
				比较值 = 角色.V白魔法 + 角色.V红魔法 + 角色.V黄魔法 + 角色.V蓝魔法 + 角色.V黑魔法
			case 5:
				比较值 = 角色.V白魔法
			case 6:
				比较值 = 角色.V红魔法
			case 7:
				比较值 = 角色.V蓝魔法
			case 8:
				比较值 = 角色.V黄魔法
			case 9:
				比较值 = 角色.V黑魔法
			}
			if 比较值 < v {
				符合 = false
				break
			}
		}
		if 符合 == false {
			continue
		}
		//再检测是关联技能
		for k, v := range v.V技能要求 {
			符合 = false
			for kk, vv := range rt.V技能列表 { //每一个角色，一定有技能，所以这里一定能进去
				技能, _ := 技能_获取技能信息(kk)
				if 技能.V技能中文名 != k {
					continue
				}
				if vv.V技能等级 >= v {
					符合 = true
				}
				break
			}
			if true == true {
				break
			}
		}
		if 符合 == false {
			continue
		}
		//全部要求已经可以了，当前可以学习了
		//先确认当前还没有学习过
		if 角色.Id == 0 {
			panic("")
		}
		rt.技能_等级增加(v.V技能英文名, 0)
	}
	return true
}
func (rt *RunTime) 技能_输出已会技能信息(技能信息 *Struct技能信息, 实时技能 *Struct实时技能信息, 可否使用 bool, tx *Buff) {
	//技能列表 := rt.V技能列表[技能信息.Id]
	//技能, _ := rt.技能_获取实时技能列表(技能信息.Id)
	if 技能信息.V攻击类型 <= 2 {
		tx.AddStringAndLen(技能信息.V技能英文名)
		tx.AddStringAndLen(技能信息.V技能类型)
		tx.AddByte(技能信息.V攻击类型)
		tx.AddInt32(int32(实时技能.V技能等级))

		tx.AddByte(0x01) //因为是把SP当经验条,所以这个SP条必须有
		tx.AddByte(0x00)
		经验值 := int32(实时技能.V经验 * 100 / 实时技能.V总经验) //由于0% 前端就会禁止使用技能,所以这里强制最低1%
		if 经验值 == 0 {
			经验值 = 1
		}

		tx.AddInt32(经验值)
		tx.AddBool(可否使用)

		tx.AddFloat(1)
		实时技能, _ := rt.技能_获取实时技能列表(技能信息.V技能英文名)
		tx.AddInt32(int32(实时技能.V攻击次数))
		tx.AddInt32(int32(实时技能.V攻击速度))
		tx.AddInt32(int32(实时技能.V攻击速度))
		tx.AddInt32(10) // 服务器计算，不通知用户
		tx.AddInt32(int32(实时技能.V魔法消耗))
	} else {
		tx.AddStringAndLen(技能信息.V技能英文名)
		tx.AddStringAndLen(技能信息.V技能中文名)
		tx.AddStringAndLen(技能信息.V技能备注)
		tx.AddInt32(int32(实时技能.V技能等级))
		tx.AddInt32(实时技能.V冷却时间)
		tx.AddInt32(int32(实时技能.V攻击速度))
		tx.AddInt32(0x00)
	}
}

//注意:  技能等级为0则表示技能不能使用
func (rt *RunTime) 技能_设置技能等级(技能信息 *Struct技能信息, 实时技能 *Struct实时技能信息, 可否使用 bool) {
	if 技能信息.V攻击类型 <= 2 {
		tx := CreateBuff(200)
		tx.AddInt16(0x00C4)
		tx.AddByte(0x2B)
		rt.技能_输出已会技能信息(技能信息, 实时技能, 可否使用, tx)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
	} else {
		tx := CreateBuff(100)
		tx.AddInt16(0x0168)
		rt.技能_输出已会技能信息(技能信息, 实时技能, 可否使用, tx)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
	}
}
func (rt *RunTime) 技能_发送学会新技能(技能信息 *Struct技能信息, 实时技能 *Struct实时技能信息) {
	if 技能信息.V攻击类型 <= 2 {
		tx := CreateBuff(200)
		tx.AddInt16(0x00C4)
		tx.AddByte(0x2C)
		rt.技能_输出已会技能信息(技能信息, 实时技能, true, tx)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
	} else {
		tx := CreateBuff(100)
		tx.AddInt16(0x0168)
		rt.技能_输出已会技能信息(技能信息, 实时技能, true, tx)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
	}

}
func (rt *RunTime) 技能_获取实时技能列表(技能英文名 string) (*Struct实时技能信息, error) {
	技能信息, err := 技能_获取技能信息_英文(技能英文名, rt.V角色.V职业)
	if err != nil {
		return nil, err
	}
	实时技能信息 := &Struct实时技能信息{}
	技能, 学会 := rt.V技能列表[技能信息.Id]
	if 学会 == false {
		技能 = &Struct技能列表{}
		实时技能信息.V技能等级 = 0
	} else {
		实时技能信息.V技能等级 = 技能.V技能等级
	}
	if rt.V角色内容 != nil {
		if 值, ok := rt.V角色内容.V基础属性[uint16(2000+技能信息.Id)]; ok == true {
			实时技能信息.V技能等级 += uint16(值)
		}
	}
	//限制技能最高等级为99级，外部显示100级
	if 实时技能信息.V技能等级 > 99 {
		实时技能信息.V技能等级 = 99
	}
	实时技能信息.V魔法消耗 = 技能信息.V魔法消耗[实时技能信息.V技能等级]
	实时技能信息.V攻击距离 = 技能信息.V攻击距离[实时技能信息.V技能等级]
	实时技能信息.V攻击速度 = 技能信息.V攻击速度[实时技能信息.V技能等级]
	实时技能信息.V攻击半径 = 技能信息.V攻击半径[实时技能信息.V技能等级]
	实时技能信息.V攻击次数 = 技能信息.V攻击次数[实时技能信息.V技能等级]
	实时技能信息.V冷却时间 = 技能信息.V冷却时间[实时技能信息.V技能等级]
	实时技能信息.V辅助时长 = 技能信息.V辅助时长[实时技能信息.V技能等级]
	实时技能信息.V基础属性 = 技能信息.V基础属性[实时技能信息.V技能等级]
	实时技能信息.V经验 = 技能.V经验
	实时技能信息.V总经验 = 技能信息.V需求经验[实时技能信息.V技能等级]

	if rt.V角色内容 == nil {
		return 实时技能信息, nil
	}

	// 减少魔法使用的魔法值
	if 值, ok := rt.V角色内容.V基础属性[E基础属性_魔法使用减少]; ok == true {
		if uint32(值) > 实时技能信息.V魔法消耗 {
			实时技能信息.V魔法消耗 = 0
		} else {
			实时技能信息.V魔法消耗 -= uint32(值)
		}
	}

	// 增加攻击距离
	if 值, ok := rt.V角色内容.V基础属性[E基础属性_增加攻击距离]; ok == true {
		实时技能信息.V攻击距离 += 值
	}

	// 增加攻击速度
	if 值, ok := rt.V角色内容.V基础属性[E基础属性_攻击速度]; ok == true {
		实时技能信息.V攻击速度 += uint16(值)
	}

	// 减小冷却时间
	if 值, ok := rt.V角色内容.V基础属性[E基础属性_减小冷却时间]; ok == true {
		if int32(值) > 实时技能信息.V冷却时间 {
			实时技能信息.V冷却时间 = 0
		} else {
			实时技能信息.V冷却时间 -= int32(值)
		}
	}
	// 增加攻击半径
	if 值, ok := rt.V角色内容.V基础属性[E基础属性_增加攻击范围]; ok == true {
		实时技能信息.V攻击半径 += 值
	}
	if 学会 == true {
		实时技能信息.V技能等级++ //0为没学会 100为满级
	}
	return 实时技能信息, nil
}
func (rt *RunTime) 技能_增加经验(技能信息 *Struct技能信息, 技能 *Struct技能列表, 经验值 int64) {
	经验值 = int64(float32(经验值) * m_历史长河.V经验倍率)
	技能.V经验 += 经验值
	技能.Stata.V修改 = true
	技能.Stata.V更新字段["V经验"] = true
	i := 0
	for ; i < 1000; i++ {
		技能 = rt.V技能列表[技能信息.Id]
		总经验 := 技能信息.V需求经验[技能.V技能等级]
		if 技能.V经验 >= 总经验 {
			rt.技能_等级增加(技能信息.V技能英文名, 技能.V技能等级+1) //这里限制最高等级1000，但是以配置表里的为准
			continue
		} else {
			经验百分比 := int(技能.V经验 * 100 / 总经验)
			if 经验百分比 != 技能.V最后经验百分比 {
				技能.V最后经验百分比 = 经验百分比
				实时技能, _ := rt.技能_获取实时技能列表(技能信息.V技能英文名)
				rt.技能_设置技能等级(技能信息, 实时技能, true) //由于是已经学会的技能，所以这里要加1
			}
		}
		break
	}
	if i >= 1000 {
		fmt.Println("循环超过次数:位置2")
	}
}
func 技能_获取指定职业技能_掩码(职业掩码 int32) []*Struct技能信息 {
	var ret []*Struct技能信息
	if m_缓存表 == false {
		var jnxx []*Struct技能信息
		if err := db.Where("技能掩码=?", 职业掩码).OrderBy("id asc").Find(&jnxx); err != nil {
			return nil
		}
		for _, 技能信息 := range jnxx {
			技能信息.F应用到变量(m_基础属性)
			ret = append(ret, 技能信息)
		}
		return ret

	} else {
		for i := 1; i < len(m_技能信息); i++ {
			if v, ok := m_技能信息[int32(i)]; ok == true {
				if v.V职业掩码 != 职业掩码 {
					continue
				}
				ret = append(ret, v)
			}
		}
		return ret
	}
}
func 技能_获取指定职业技能(职业 string) []*Struct技能信息 {
	var ret []*Struct技能信息
	if m_缓存表 == false {
		var jnxx []*Struct技能信息
		if err := db.Where("技能的职业=?", 职业).OrderBy("Id asc").Find(&jnxx); err != nil {
			panic(err)
		}
		for _, 技能信息 := range jnxx {
			技能信息.F应用到变量(m_基础属性)
			ret = append(ret, 技能信息)
		}
		return ret

	} else {
		for i := 1; i < len(m_技能信息); i++ {
			if v, ok := m_技能信息[int32(i)]; ok == true {
				if v.V技能的职业 != 职业 {
					continue
				}
				ret = append(ret, v)
			}
		}
		return ret
	}
}
func 技能_获取技能信息(id int32) (*Struct技能信息, error) {
	if id == 0 {
		return nil, errors.New("不存在的技能")
	}
	if m_缓存表 == false {
		技能信息 := &Struct技能信息{Id: id}
		if ok, _ := db.Get(技能信息); ok == false {
			return nil, sql.ErrNoRows
		}
		技能信息.F应用到变量(m_基础属性)
		return 技能信息, nil
	} else {
		if t, ok := m_技能信息[id]; ok == false {
			return nil, errors.New("未知ID")
		} else {
			return t, nil
		}
	}
}
func 技能_获取技能信息_中文(技能中文名 string) (*Struct技能信息, error) {

	if m_缓存表 == false {
		技能信息 := &Struct技能信息{}
		if ok, _ := db.Where("技能中文名=?", 技能中文名).Get(技能信息); ok == false {
			return nil, sql.ErrNoRows
		}
		技能信息.F应用到变量(m_基础属性)
		return 技能信息, nil
	} else {
		for _, v := range m_技能信息 {
			if v.V技能中文名 != 技能中文名 {
				continue
			}
			return v, nil
		}
		return nil, errors.New("未知技能")
	}
}
func 技能_获取技能信息_英文(技能英文名 string, 职业 string) (*Struct技能信息, error) {
	if m_缓存表 == false {
		技能信息 := &Struct技能信息{}
		if ok, _ := db.Where("技能英文名=?", 技能英文名).Where("技能的职业", 职业).Get(&技能信息); ok == false {
			return nil, sql.ErrNoRows
		}
		技能信息.F应用到变量(m_基础属性)
		return 技能信息, nil
	} else {
		for _, v := range m_技能信息 {
			if v.V技能英文名 != 技能英文名 {
				continue
			}
			if v.V技能的职业 != 职业 {
				continue
			}
			return v, nil
		}
		return nil, errors.New("未知技能")
	}
}
